package good_src.Implementation;

import good_src.Interfaces.Algorithme;
import good_src.Interfaces.Capteur;
import good_src.Interfaces.ObservateurCapteur;
import good_src.Strategy.EpoqueStrategy;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Observable;
import java.util.Observer;
import java.util.Random;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;

/**
 * 
 * @author Tangi Midy & Fabien Le Peih
 * Capteur Realization
 */
public class ConcreteCapteur extends Observable implements Capteur<Integer> {

	private Collection<Canal> canaux;
	private int value;
	/**
	 * The scheduler of the active objects pattern
	 */
	private ScheduledExecutorService scheduler;
	private Collection<ObservateurCapteur> observers;
	private boolean ticking = true;
	private Algorithme algorithme;

	/**
	 * Constructor of the class instanciates the scheduler and the observers
	 * list associates observers and Subject
	 */
	public ConcreteCapteur() {
		this.value = 0;
		scheduler = new ScheduledThreadPoolExecutor(20);
		observers = new ArrayList<ObservateurCapteur>();
	}

	/**
	 * @see good_src.Interfaces.Subject#setCanaux(int)
	 */
	@Override
	public void setCanaux(int displayers) {
		Canal c;
		for (int i = 1; i <= displayers; i++) {
			c = new Canal(this);
			c.setScheduler(scheduler);

			c.setName(String.valueOf(i));
			observers.add(c);
		}
	}

	/**
	 * Set the used strategy
	 * 
	 * @param algo
	 *            the distribution strategy
	 */
	@Override
	public void setStrategy(Algorithme algo) {
		this.algorithme = algo;
		algorithme.configure();
	}

	/**
	 * 
	 * @see good_src.Interfaces.Capteur#update()
	 */
	@Override
	public void tick() {
		Random r = new Random();
		
		if (isTicking()) {

			this.value++;
	//		this.value=r.nextInt();
			
			if (getStrategy() != null) {
				if (getStrategy().getClass().getSimpleName().equals("Atomique")) {
					// Atomic Strategy
					Thread t = new Thread((Runnable) algorithme);
					t.start();
				} else {
					algorithme.execute();
				}
			} else {
				for (ObservateurCapteur c : getObservers()) {
					c.update();
				}
			}

		}
	}

	/**
	 * 
	 * @see good_src.Interfaces.Subject#getStrategy()
	 */
	@Override
	public Algorithme getStrategy() {
		return algorithme;
	}

	/**
	 * 
	 * @see good_src.Interfaces.Subject#getVersion()
	 */
	@Override
	public int getVersion() {
		if (algorithme!=null){
			if (algorithme.getClass().getSimpleName().equals("EpoqueStrategy")) {
				return ((EpoqueStrategy) algorithme).getVersion();
			}
		}
		return -1;
	}

	/**
	 * 
	 * @see good_src.Interfaces.Subject#attach(java.util.Observer)
	 */
	@Override
	public void attach(Observer observer) {
		// observers.add(observer);
	}

	/**
	 * 
	 * @see good_src.Interfaces.Subject#detach(java.util.Observer)
	 */
	@Override
	public void detach(Observer observer) {
		// observers.remove(observer);
	}

	/**
	 * Getter of the property <tt>canal</tt>
	 * 
	 * @return Returns the canal.
	 * 
	 */
	public Collection<Canal> getCanaux() {
		return canaux;
	}

	@Override
	public Integer getValue() {
		return value;
	}

	/**
	 * 
	 * @see good_src.Interfaces.Capteur#update()
	 */
	@Override
	public void update() {

	}

	/**
	 * 
	 * @see Interfaces.Capteur#isTicking()
	 */
	@Override
	public boolean isTicking() {
		return ticking;
	}

	/**
	 * 
	 * @see Interfaces.Capteur#setTick(boolean)
	 */
	@Override
	public void setTick(boolean b) {
		ticking = b;
	}

	/**
	 * 
	 * @see Interfaces.Capteur#getObservers()
	 */
	@Override
	public Collection<ObservateurCapteur> getObservers() {
		return observers;
	}

}
